﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Linq;

namespace MidnightPeach.SolutionCreating
{
    public static class SolutionCreator
    {
        private const string DefaultSolutionName = "AdventureWorks";

        private static string _solutionName;

        private static readonly Dictionary<string, string> _dictionary = new Dictionary<string, string>();

        public static string SolutionFilePath { get; private set; }

        public static IEnumerable<string> GetDirectoryNames()
        {
            var query = from x in Directory.GetDirectories("SolutionCreating")
                        select x.Split(new[] {"\\"}, StringSplitOptions.RemoveEmptyEntries)[1];

            string[] latestFolderNames = { "Entity Framework 1.0", "LINQ to SQL 1.0" };

            return query.Where(latestFolderNames.Contains);
        }

        /// <summary>
        /// 솔루션을 생성한다.
        /// </summary>
        /// <param name="solutionTemplate">생성할 솔루션 템플릿</param>
        /// <param name="solutionName">솔루션의 이름</param>
        /// <param name="directory">솔루션이 생성될 부모 디렉토리.</param>
        /// <returns>성공시 null, 실패시 예외 메시지</returns>
        public static string Create(string solutionTemplate, string solutionName, string directory)
        {
            try
            {
                _solutionName = solutionName;
                string solutionDirectory = Path.Combine(directory, _solutionName);

                _dictionary.Clear();

                _dictionary.Add("$SolutionName$", _solutionName);
                _dictionary.Add("$SolutionDirectory$", solutionDirectory);
                _dictionary.Add("$SolutionID$", Guid.NewGuid().ToUpper());
                _dictionary.Add("$SolutionItemGroupID$", Guid.NewGuid().ToUpper());
                _dictionary.Add("$SolutionFileID1$", Guid.NewGuid().ToUpper());
                _dictionary.Add("$SolutionFileID2$", Guid.NewGuid().ToUpper());
                
                _dictionary.Add("$DataID$", Guid.NewGuid().ToUpper());
                _dictionary.Add("$DataComID$", Guid.NewGuid().ToUpper());
                _dictionary.Add("$DataItemGroupID$", Guid.NewGuid().ToUpper());
                
                _dictionary.Add("$ServiceID$", Guid.NewGuid().ToUpper());
                _dictionary.Add("$ServiceComID$", Guid.NewGuid().ToUpper());
                _dictionary.Add("$ServiceItemGroupID$", Guid.NewGuid().ToUpper());
                
                _dictionary.Add("$BizID$", Guid.NewGuid().ToUpper());
                _dictionary.Add("$BizComID$", Guid.NewGuid().ToUpper());
                _dictionary.Add("$BizItemGroupID$", Guid.NewGuid().ToUpper());
                
                _dictionary.Add("$TestConsoleID$", Guid.NewGuid().ToUpper());
                _dictionary.Add("$TestConsoleComID$", Guid.NewGuid().ToUpper());
                _dictionary.Add("$TestConsoleItemGroupID$", Guid.NewGuid().ToUpper());
                
                CopyFolder("SolutionCreating\\" + solutionTemplate, solutionDirectory);

                StartReplacing(solutionDirectory);

                SolutionFilePath = Path.Combine(solutionDirectory, _solutionName + ".sln");

                return null;
            }
            catch (Exception ex)
            {
                return ex.Message;
            }
        }

        private static void StartReplacing(string root)
        {
            var files = Directory.GetFiles(root);

            foreach (var file in files)
            {
                if (Path.GetExtension(file) != ".mps")
                    continue;

                var replacedText = ReplaceFile(file);
                File.WriteAllText(file, replacedText, Encoding.UTF8);

                var renamedFile = file.ReplaceFileName(DefaultSolutionName, _solutionName);
                File.Move(file, renamedFile);
            }

            var directories = Directory.GetDirectories(root);
            foreach (var directory in directories)
            {
                StartReplacing(directory);

                var renamedDirectory = directory.ReplaceDirectoryName(DefaultSolutionName, _solutionName);
                if (directory != renamedDirectory)
                    Directory.Move(directory, renamedDirectory);
            }
        }

        private static string ReplaceFile(string file)
        {
            var text = File.ReadAllText(file);

            foreach (var item in _dictionary)
                text = text.Replace(item.Key, item.Value);

            return text;
        }

        private static void CopyFolder(string sourceFolder, string outputFolder)
        {
            Directory.CreateDirectory(outputFolder);
            string[] files = Directory.GetFiles(sourceFolder);
            foreach (string file in files)
            {
                File.Copy(file, Path.Combine(outputFolder, Path.GetFileName(file)), true);
            }
            string[] folders = Directory.GetDirectories(sourceFolder);
            foreach (string folder in folders)
            {
                string[] splitFolders = folder.Split('\\');
                string folderName = splitFolders[splitFolders.Length - 1];
                CopyFolder(folder, Path.Combine(outputFolder, folderName));
            }
        }
    }

    public static class GuidExtensions
    {
        public static string ToUpper(this Guid guid)
        {
            return guid.ToString("D").ToUpper();
        }
    }

    public static class StringExtensions
    {
        public static string ReplaceFileName(this string text, string source, string target)
        {
            var file = Path.GetFileName(text);
            var directory = Path.GetDirectoryName(text);
            var path = Path.Combine(directory, file.Replace(source, target));

            return path.Substring(0, path.Length - 4);
        }

        public static string ReplaceDirectoryName(this string text, string source, string target)
        {
            var tokens = text.Split('\\');
            tokens[tokens.Length - 1] = tokens[tokens.Length - 1].Replace(source, target);

            return string.Join("\\", tokens);
        }
    }
}